每個工作節點上負責監控Pod存活性的角色是kubelet, 它會在主容器發生錯誤時進行自我修復, 但它只能監控主容器, 其餘的項目發生錯誤時需要依靠Pod設定的存活性探測機制來得知,
但是在工作節點自身發生錯誤的時候kubelet也不能再使用了, 此時Master無法得知工作節點的狀態, Pod也無法再重啟; 這時候就需要透過工作節點之外的Controller來監控, Controller是K8s Master的 kube-controller-manager上的一個組件, kube-controller-manager的任務是要確保object的status要符合object部署的spec, 它會不斷的進行status和spec的和解reconciliation來確保Pod的狀態, 常見的controller有 Namespace Controller, Deployment Controller, Service Controller...等, 可以將 Pod Controller視為一個監督者的角色, 它位在Pod工作節點外的上一層, 負責確保Pod有依照用戶設定的內容運作。

圖片參考書:【Kubernetes 進階實踐】
Pod模板是Controller拿來創建或管理Pod的參考規範,Pod spec通常都必須具備replicas,selector,template, 模板就是spec中的 template字段; 由於template是要嵌入Controller中使用, 所以不會有apiVersion, kind字段,
修改或更新template並不會更新已存在的Pod, 而是由Controller偵測到spec更新而創建一個新的Pod, 同時檢查Pod的狀態是否符合spec, 不符合spec的pod 將會被終止。
ReplicaSet 是用來確保Pod的運作狀態要符合pod spec配置的一種實現, 它啟動後會在cluster中匹配和 label selector 相符的object, 並反覆確認pod個數是否符合spec期望, 如果有多會刪除, 有少則會透過 PodTemplate 創建Pod補足, 等到狀態符合期望之後, ReplicaSet 會再進入下一個循環。
圖片參考書:【Kubernetes 進階實踐】
配置 ReplicaSet spec 一樣需要 apiVersion, kind, metadata, spec, 針對 spec 底下還有幾個屬性:
* replicas : 期望的pod數量
* selector : Controller匹配Pod數量的label selector, 支援 matchLabels 和 matchExpressions
* template : 用來補足Pod數量時所用的Pod模板
* minReadySeconds : 新建的Pod在啟動後多長時間內未發生錯誤即視為Ready, 預設0秒。
### 創建範例 YAML
apiVersion: apps/v1
kind: ReplicaSet
  metadata:
    name: rs-example
  spec:
    replicas: 2
    selector:
      matchLabels:
        app: rs-demo
    template:
      metadata:
        labels:
          app: rs-demo
      spec:
        containers:
        - name: rs-hello
          image: nginx:latest
          ports:
          - name: http
            containerPort: 80
    minReadySeconds: 5
執行
-> % kubectl apply -f replica-demo.yaml
replicaset.apps/rs-example configured
查看狀態
-> % kubectl get pods -l app=rs-demo
NAME               READY   STATUS              RESTARTS   AGE
rs-example-44nhn   0/1     ContainerCreating   0          4s
rs-example-mgjcr   0/1     ContainerCreating   0          4s
第一次key錯image, 查看狀態時回應如下
-> % kubectl get pods -l app=rs-demo
NAME               READY   STATUS         RESTARTS   AGE
rs-example-44nhn   0/1     ErrImagePull   0          11s
rs-example-mgjcr   0/1     ErrImagePull   0          11s
修改image來源之後查看狀態還是不成功(因為replicaSet的YAML修改只對新建的pod生效)
-> % kubectl get pods -l app=rs-demo
NAME               READY   STATUS             RESTARTS   AGE
rs-example-44nhn   0/1     ImagePullBackOff   0          28s
rs-example-mgjcr   0/1     ImagePullBackOff   0          28s
此時操作刪除Pod讓它自動重新建立
kubectl delete pod rs-example-mgjcr
kubectl delete pod rs-example-44nhn
載入修改後image的pod狀態已是Running
-> % kubectl get pods -l app=rs-demo
NAME               READY   STATUS    RESTARTS   AGE
rs-example-nvwqp   1/1     Running   0          9s
rs-example-tcckz   1/1     Running   0          18s
Pod創建後, ReplicaSet就不會再去檢查pod spec內容, 所以除了修改pod副本個數之外, 其餘的變動都要在下一個新的pod創建時才會生效。ReplicaSet 可以確保Pod數量精確符合期望值, 發現Pod不健康時會自動請求創建Pod副本以及隨著設定彈性伸縮pod規模。
ReplicaSet 是按照 label selector 來匹配pod數量, 如果手動去修改 label 也會觸發 ReplicaSet 自動創建的機制
-> % kubectl get pods  -L app
NAME                            READY   STATUS              RESTARTS   AGE     APP
rs-example-cwn9x                1/1     Running             0          4m14s   rs-demo
rs-example-jbm28                1/1     Running             0          4m14s   rs-demo
-> % kubectl label pods rs-example-cwn9x app= --overwrite
pod/rs-example-cwn9x labeled
-> % kubectl get pods  -L app
NAME                                READY   STATUS    RESTARTS   AGE     APP
rs-example-cwn9x                    1/1     Running   0          5m26s
rs-example-jbm28                    1/1     Running   0          4m59s   rs-demo
rs-example-v94sf                    1/1     Running   0          13s     rs-demo
原本的 rs-example-cwn9x 因為強制更新了label 所以ReplicaSet檢查的時候不會計算它, 為了達到期望的2個, 於是創建了一個新的 rs-example-v94sf
-> % kubectl label pods rs-example-cwn9x app=rs-demo --overwrite
pod/rs-example-cwn9x labeled
-> % kubectl get pods  -L app
NAME                                READY   STATUS        RESTARTS   AGE     APP
rs-example-cwn9x                    1/1     Running       0          9m28s   rs-demo
rs-example-jbm28                    1/1     Running       0          9m1s    rs-demo
rs-example-v94sf                    0/1     Terminating   0          4m15s   rs-demo
因為 rs-example 只能有兩個pod, 當 label掃到有三個pod的時候, 會把其中一個pod刪除, 所以 rs-example-v94sf 狀態為 Terminating
kubectl 提供了一個指令可以實現 ReplicaSet 的伸縮
kubectl scale replicasets [LABEL] --replicas=<integer>
-> % kubectl get replicasets
NAME                          DESIRED   CURRENT   READY   AGE
rs-example                    2         2         2       50m
-> % kubectl scale replicasets rs-example --replicas=3
replicaset.apps/rs-example scaled
-> % kubectl get replicasets
NAME                          DESIRED   CURRENT   READY   AGE
rs-example                    3         3         3       51m
另外kubectl 還提供參數 --current-replicas 可以依照現在pod數量判斷擴充條件
--current-replicas條件所以不會執行-> % kubectl scale replicasets rs-example --current-replicas=2 --replicas=3
 error: Expected replicas to be 2, was 3
-> % kubectl scale replicasets rs-example --current-replicas=3 --replicas=5
replicaset.apps/rs-example scaled
-> % kubectl get replicasets
NAME                          DESIRED   CURRENT   READY   AGE
rs-example                    5         5         5       57m
預設刪除ReplicaSet 時會一併刪除下層的pod, kubectl 有提供參數 --cascade=false 供使用, 可以只刪除 replicaset
由於replicaset不支援滾動更新,所以大多建議使用deployment,下一篇會研究看看deployment。